import ast
import operator
import os
import shutil
import cv2 as cv
import pandas as pd
from functools import reduce
from PyQt5.QtGui import QPixmap, QImage, QCursor, QFont, QWheelEvent, QMouseEvent
from PyQt5.QtWidgets import QMainWindow, QGraphicsScene, QGraphicsPixmapItem, QMessageBox, QLabel, QGraphicsItem
from PyQt5.QtCore import Qt, pyqtSignal
from UI.ui_image_view import Ui_image_view
from service.utils import ImageShow


class ImageView(QMainWindow, Ui_image_view):

    _signal = pyqtSignal(str)

    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.retranslateUi(self)
        self.scene = QGraphicsScene()
        self.area_pos = []
        self.expect_img = None
        self.replay_img = None
        self.record_data = None
        self.replay_data = None
        self.img_w = -1
        self.img_h = -1
        self.area_ptn.clicked.connect(self.show_area_img)
        self.replace_btn.clicked.connect(self.replace_expect_image)

    def open_window(self):
        self.show()

    def closeEvent(self, event):
        result = QMessageBox.question(
            self, "提示", "确定退出?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if result == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

    def set_status_bar(self):
        self.status_lab = QLabel()
        self.status_lab.setStyleSheet('color: red')
        self.status_lab.setFont(QFont("Roman times", 10, QFont.Bold))
        self.status_lab.clear()
        return self.status_lab

    def paint_img(self, gv, image, flag=True):
        scene = QGraphicsScene()
        scene.clear()
        gv.setScene(scene)
        frame = QImage(image)
        pix = QPixmap.fromImage(frame)
        item = QGraphicsPixmapItem(QPixmap(frame))
        scene.clear()
        scene.addItem(item)
        item.setTransformationMode(Qt.SmoothTransformation)
        gv.fitInView(item, Qt.KeepAspectRatio)
        if flag:
            scene.mouseReleaseEvent = self.mouseReleaseEvent
        else:
            item.setFlags(QGraphicsItem.ItemIsMovable |
                          QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable)

    def show_image(self, image, gv, img_flag, record_data, replay_data):
        self.record_data = record_data
        self.replay_data = replay_data
        img = cv.imread(image)
        self.img_w = img.shape[0]
        self.img_h = img.shape[1]
        if img_flag == 1:
            self.expect_gv = gv
            self.expect_img = image
            self.paint_img(self.expect_gv, image, True)
        if img_flag == 2:
            self.run_gv = gv
            self.replay_img = image
            self.paint_img(self.run_gv, image, False)

    def wheelEvent(self, event: QWheelEvent):
        if self.run_gv.geometry().contains(self.mapFromGlobal(QCursor.pos())):
            img = self.run_gv.geometry()
            img_x = img.x()+self.img_w-5
            img_y = img.y() + self.img_h-5
            if event.pos().x() <= img_x and event.pos().y() <= img_y:
                if event.angleDelta().y() > 0:
                    self.run_gv.scale(1.09, 1.09)
                else:
                    self.run_gv.scale(0.91, 0.91)

    def mouseReleaseEvent(self, event: QMouseEvent):
        if event.button() == Qt.MidButton:
            x = event.scenePos().x()
            y = event.scenePos().y()
            pos = int(x), int(y)
            self.area_pos.append(pos)
        if len(self.area_pos) == 2 and os.path.exists(self.expect_img):
            pos = list((map(list, self.area_pos)))
            pos = reduce(operator.concat, pos)
            if all(item > 0 for item in pos):
                self.update_data(self.record_data,
                                 self.replay_data, self.area_pos)
                min_x = self.area_pos[0][0]
                min_y = self.area_pos[0][1]
                width = abs(self.area_pos[0][0]-self.area_pos[1][0])
                height = abs(self.area_pos[0][1]-self.area_pos[1][1])
                excp_img = cv.imread(self.expect_img)
                roi_img = excp_img[min_y:min_y+height, min_x:min_x+width]
                # cv.rectangle(
                #     excp_img, self.area_pos[0], self.area_pos[1], (0, 0, 255), 1)
                # cv.imshow("select-area-image", roi_img)
                # cv.moveWindow("select-area-image", 100, 100)
                # cv.setWindowProperty(
                #     "select-area-image", cv.WND_PROP_TOPMOST | cv.WND_PROP_FULLSCREEN, 1)
                self.area_pos = []
                self.img = ImageShow(roi_img)
                self.img.show()
            else:
                self.area_pos = []
                QMessageBox.critical(self, "错误", "区域点超出图片范围!")

    def update_data(self, record_data, replay_data, area_pos):
        title = self.windowTitle()
        step = title[3:len(title)].split("步")[0]
        if os.path.exists(record_data) and os.path.isfile(record_data):
            record_df = pd.read_csv(record_data, index_col=0)
            if '比对区域' not in record_df.columns.to_list():
                record_df.columns.to_list().insert(4, '比对区域')
                record_df.reindex(columns=record_df.columns.to_list())
                record_df.insert(loc=4, column='比对区域', value='')
            record_df['比对区域'] = record_df['比对区域'].astype('object')
            record_df.at[int(step), '比对区域'] = area_pos
            record_df.to_csv(
                record_data, columns=record_df.columns.to_list(), encoding='utf_8_sig')
            self._signal.emit(record_data)
        if os.path.exists(replay_data) and os.path.isfile(replay_data):
            replay_df = pd.read_csv(replay_data, index_col=0)
            if '比对区域' not in replay_df.columns.to_list():
                replay_df.columns.to_list().insert(4, '比对区域')
                replay_df.reindex(columns=replay_df.columns.to_list())
                replay_df.insert(loc=4, column='比对区域', value='')
            replay_df['比对区域'] = replay_df['比对区域'].astype('object')
            replay_df.at[int(step), '比对区域'] = area_pos
            replay_df.to_csv(
                replay_data, columns=replay_df.columns.to_list(), encoding='utf_8_sig')
            self._signal.emit(replay_data)

    def show_area_img(self):
        title = self.windowTitle()
        step = title[3:len(title)].split("步")[0]
        if os.path.exists(self.record_data):
            record_df = pd.read_csv(self.record_data, index_col=0)
            if '比对区域' not in record_df.columns.to_list():
                record_df.insert(loc=4, column='比对区域', value='')
            record_df['比对区域'] = record_df['比对区域'].astype('object')
            area_pos = record_df.at[int(step), '比对区域']
            if not pd.isna(area_pos) and area_pos != '':
                area_pos = ast.literal_eval(area_pos)
                min_x = area_pos[0][0]
                min_y = area_pos[0][1]
                width = abs(area_pos[0][0]-area_pos[1][0])
                height = abs(area_pos[0][1]-area_pos[1][1])
                excp_img = cv.imread(self.expect_img)
                roi_img = excp_img[min_y:min_y+height, min_x:min_x+width]
                # cv.imshow("select-area-image", roi_img)
                # cv.moveWindow("select-area-image", 100, 100)
                # cv.setWindowProperty("select-area-image",
                #                      cv.WND_PROP_TOPMOST | cv.WND_PROP_FULLSCREEN, 1)
                self.img = ImageShow(roi_img)
                self.img.show()
                self.pre_btn.clicked.connect(self.img.close)
                self.next_btn.clicked.connect(self.img.close)
            else:
                QMessageBox.critical(self, "错误", "比对区域不存在!")

    def msg_window(self, title="警告", info="", btny_txt="Yes", btnx_txt="No", flag=True):
        self.showMinimized()
        msg_box = QMessageBox(self)
        msg_box.setWindowTitle(title)
        msg_box.setText(info)
        if flag:
            msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            btn_y = msg_box.button(QMessageBox.Yes)
            btn_n = msg_box.button(QMessageBox.No)
            btn_y.setText(btny_txt)
            btn_n.setText(btnx_txt)
            msg_box.exec_()
            if msg_box.clickedButton() == btn_y:
                msg_box.deleteLater()
                return 1
            elif msg_box.clickedButton() == btn_n:
                msg_box.deleteLater()
                return 2

    def replace_expect_image(self):
        if self.replay_data!=None:
            title = self.windowTitle()
            step = title[3:len(title)].split("步")[0]
            record_path = os.path.dirname(self.record_data)
            replay_path = os.path.dirname(self.replay_data)
            record_replace_img = os.path.join(
                record_path, 'expect_image', str(step)+'.png')
            replay_replace_img = os.path.join(
                replay_path, 'runtime_image', str(step)+'.png')
            if os.path.exists(record_replace_img) and os.path.exists(replay_replace_img):
                ret = self.msg_window(info="是否将当前运行结果图片替换为当前步骤预期结果图片？")
                if ret == 1:
                    shutil.copy2(replay_replace_img, record_replace_img)
                    self.scene.clear()
                    except_img = os.path.join(
                        record_path, 'expect_image', str(step)+'.png')
                    self.paint_img(self.expect_gv, except_img, True)
        else:
            QMessageBox.critical(self, "错误", "不存在回放数据!")
